#ifndef __COMM_HPP__
#define __COMM_HPP_
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <fcntl.h>
#include <string>
#include <unistd.h>
using namespace std;

#define PATHNAME "."
#define PROJ_ID 88
#define SIZE 4096

char* ready = "I am ready";

key_t getkey()
{
    key_t k = ftok(PATHNAME, PROJ_ID);
    assert(k);
    return k;
}

static int ShmHelper(key_t key, int size, int flags)
{
    int shmid = shmget(key, size, flags);
    if(shmid == -1)
    {
        cout << errno << ": " << strerror(errno) << endl;
        exit(1);
    }

    return shmid;
}

int createShm(key_t key, int size) 
{
    return ShmHelper(key, size, IPC_CREAT | IPC_EXCL | 0666); 
}

int getShm(key_t key, int size)
{
    return ShmHelper(key, size, IPC_CREAT);
}

char* attachShm(int shmid) // 链接共享库
{
    char* start = (char*)shmat(shmid, nullptr, 0);
    return start;
}

void detaShm(char* start) // 断开链接
{
    int n = shmdt(start);
    if(n == -1)
    {
        cout << errno << ": " << strerror(errno) << endl;
        exit(1);
    }
    // assert(n);
    // (void)n;
}

void delShm(int shmid) // 删除共享库
{
    int n = shmctl(shmid, IPC_RMID, nullptr);
    if(n == -1)
    {
        cout << errno << ": " << strerror(errno) << endl;
        exit(1);
    }
    // assert(n);
    // (void)n;
}

#define SERVER 1
#define CLIENT 0
#define SERVER_PATH "server.pipe"
#define CLIENT_PATH "client.pipe"
mode_t mode = 0666;
// 对共享内存的所有功能封装
class Init
{
public:
    Init(int type) :_type(type)
    {
        if(type == 1)
        {
            _shmid = createShm(getkey(), SIZE);
            mkfifo(SERVER_PATH, mode);
            mkfifo(CLIENT_PATH, mode);
        }
        else
        {
            _shmid = getShm(getkey(), SIZE);
        }

        _start = attachShm(_shmid);
    }

    int* PipeOpen()
    {

        if(_type == 1)
        {
            fd[0] = open(CLIENT_PATH, O_RDONLY); // 要同时打开一方的读写端
            fd[1] = open(SERVER_PATH, O_WRONLY); // 不能同时打开两方的读端或写端，会造成阻塞
        }
        else
        {
            fd[1] = open(CLIENT_PATH, O_WRONLY);
            fd[0] = open(SERVER_PATH, O_RDONLY);
        }

        return fd;
    }

    char* GetStart()
    {
        return _start;
    }

    ~Init()
    {
        detaShm(_start);

        if(_type == 1)
        {
            delShm(_shmid);
            unlink(SERVER_PATH);
            unlink(CLIENT_PATH);
        }

        close(fd[0]); 
        close(fd[1]);
    }

protected:
    int _shmid;
    char* _start;
    int _type; // 通过 0 1 控制用户端和服务端
    int fd[2];
};







#endif